import { ChunkType, Context, Module } from '../../core';
import { CssAst, ScriptAst } from '../../types';
import astToCode from '@babel/generator';

export function generateChunksCode(context: Context) {
  const chunks = context.chunkGraph.getChunks();
  chunks.forEach(chunkId => {
    const chunk = context.chunkGraph.getChunk(chunkId);
    const modules = chunk.modules.map(moduleId => context.moduleGraph.getModule(moduleId));
    if (chunk.type === ChunkType.Js) {
      chunk.code = generateRuntimeCode(modules, context.config.entry);
    } else if (chunk.type === ChunkType.Css) {
      chunk.code = generateCssCode(modules);
    }
  });
}

function generateRuntimeCode(modules: Module[], entryModule: string) {
  const modulesObjExpr = modules.map(module => {
    return `"${module.id}": function(module, exports, require) {
      ${astToCode((module.ast as ScriptAst)).code}
    },`;
  }).join('\n');

  return resolveRuntimeCode(`{${modulesObjExpr}}`, entryModule);
}

function generateCssCode(modules: Module[]) {
  let code = '';
  modules.forEach(module => {
    // console.log((module.ast as CssAst).toString());
    code += (module.ast as CssAst).toString();
  });
  return code;
}

function resolveRuntimeCode(modulesObjExpr: string, entryModule: string) {
  return `
(function (modules, entryModule) {
  var cache = {};

  function require(id) {
    if (cache[id]) return cache[id].exports;

    var module = {
      id: id,
      exports: {}
    };

    modules[id](module, module.exports, require);
    cache[id] = module;
    return module.exports;
  }

  require(entryModule);
})(${modulesObjExpr}, "${entryModule}");
  `.trim();
}
